View Javadoc

1   package joeq.Util;
2   
3   /***
4    * Based on code from AspectWerks and slightly modified.
5    * 
6    *  The original can be found here:
7    *  
8    *  @url http://cvs.codehaus.org/viewrep/~raw,r=1.3/aspectwerkz/aspectwerkz4/src/main/org/codehaus/aspectwerkz/definition/DescriptorUtil.java
9    * */
10  
11  import java.util.HashMap;
12  import java.util.Map;
13  import java.util.StringTokenizer;
14  
15  /***
16   * The signature of a method that is available from the BCEL library uses descriptors as defined in Section 4.3 of the
17   * Java Virtual Machine specificaiton. Javadoc and Java do not use signatures in this same format. This class converts
18   * the Javadoc/Java signature format to that used by the JVM spec. To summarize the descriptors <code> A method
19   * descriptor represents the parameters that the method takes and the value that it returns:
20   * <p/>
21   * MethodDescriptor: ( ParameterDescriptor* ) ReturnDescriptor
22   * <p/>
23   * A parameter descriptor represents a parameter passed to a method:
24   * <p/>
25   * ParameterDescriptor: FieldType
26   * <p/>
27   * A return descriptor represents the type of the value returned from a method. It is a series of characters generated
28   * by the grammar:
29   * <p/>
30   * ReturnDescriptor: FieldType V
31   * <p/>
32   * The character V indicates that the method returns no value (its return type is void). </code>
33   * <p/>
34   * <code> A field descriptor represents the type of a class, instance, or local variable. It is a series of characters
35   * generated by the grammar:
36   * <p/>
37   * FieldDescriptor: FieldType
38   * <p/>
39   * ComponentType: FieldType
40   * <p/>
41   * FieldType: BaseType ObjectType ArrayType
42   * <p/>
43   * BaseType: B C D F I J S Z
44   * <p/>
45   * ObjectType: L <classname> ;
46   * <p/>
47   * ArrayType: [ ComponentType
48   * <p/>
49   * The characters of BaseType, the L and ; of ObjectType, and the [ of ArrayType are all ASCII characters. The
50   * <classname> represents a fully qualified class or interface name. For historical reasons it is encoded in internal
51   * form (4.2).  The interpretation of the field types is as shown in Table 4.2.
52   * <p/>
53   * BaseType Character  Type       Interpretation ---------------------------------------------- B                   byte
54   * signed byte C                   char       Unicode character D                   double     double-precision
55   * floating-point value F                   float      single-precision floating-point value I                   int
56   * integer J                   long       long integer L<classname>;       reference  an instance of class <classname> S
57   * short      signed short Z                   boolean    true or false [ reference  one array dimension
58   *
59   * @author <a href="mailto:mpollack@speakeasy.org">Mark Pollack</a>
60   */
61  public class DescriptorUtil {
62      private static Map _paramTypeMap = new HashMap();
63  
64      private static Map _returnTypeMap = new HashMap();
65  
66      static {
67          _paramTypeMap.put("byte", "B");
68          _paramTypeMap.put("char", "C");
69          _paramTypeMap.put("double", "D");
70          _paramTypeMap.put("float", "F");
71          _paramTypeMap.put("int", "I");
72          _paramTypeMap.put("long", "J");
73  
74          //todo: make generic...look for 'dots' of package. that algorithm doesn't handle
75          // packageless (default package)
76          // classes though..
77          _paramTypeMap.put("java.lang.Object", "Ljava/lang/Object;");
78          _paramTypeMap.put("short", "S");
79          _paramTypeMap.put("boolean", "Z");
80  
81          //todo
82          _paramTypeMap.put("array reference", "[");
83          _returnTypeMap.put("void", "V");
84      }
85  
86      /***
87       * Converts from the Java/Javadoc method signature the JVM spec format.
88       *
89       * @param javadocSig        method signature as returned via Javadoc API.
90       * @param javadocReturnType return type as returned via Javadoc API.
91       * @return mtehod signature as defined in the JVM spec.
92       */
93      public static String convert(String javadocSig, String javadocReturnType) {
94          //remove the leading and trailing parens
95          String javadocSigTrim = javadocSig.substring(1, javadocSig.length() - 1);
96          StringTokenizer st = new StringTokenizer(javadocSigTrim, ",");
97          StringBuffer jvmBuff = new StringBuffer("(");
98          while (st.hasMoreTokens()) {
99              //remove the leading space character.
100             String sigElement = st.nextToken().trim();
101             if (_paramTypeMap.containsKey(sigElement)) {
102                 jvmBuff.append(_paramTypeMap.get(sigElement));
103             }
104         }
105         jvmBuff.append(")");
106         if (_returnTypeMap.containsKey(javadocReturnType)) {
107             jvmBuff.append(_returnTypeMap.get(javadocReturnType));
108         }
109         return jvmBuff.toString();
110     }
111 
112     /***
113      * Convert a JVM signature as defined in the JVM spec to that used in the Java.
114      *
115      * @param jvmSignature The JVM format signature.
116      * @return a <code>String[]</code> containing the method parameter as elements of the array.
117      */
118     public static String[] getParameters(final String jvmSignature) {
119         int i = 0;
120         if (jvmSignature.charAt(i) != '(') {
121             return null;
122         }
123         int j = 0;
124         StringBuffer stringbuffer = new StringBuffer();
125         for (i++; i < jvmSignature.length();) {
126             if (jvmSignature.charAt(i) == ')') {
127                 i++;
128                 break; //we are at the end of the signature.
129             }
130             if (i > 1) {
131                 //put in spaces to later tokenize on.
132                 stringbuffer.append(" ");
133             }
134             i = jvmFormatToJavaFormat(jvmSignature, i, stringbuffer);
135 
136             //count number of elements parsed.
137             j++;
138         }
139 
140         //convert to string array.
141         String convertedString = stringbuffer.toString();
142         String[] as = new String[j];
143         int k = 0;
144         StringTokenizer st = new StringTokenizer(convertedString);
145         while (st.hasMoreTokens()) {
146             as[k++] = st.nextToken();
147         }
148         return as;
149     }
150 
151     /***
152      * The utility method that does the real work of parsing through the JVM formatted string and adding an converted
153      * method parameter description to the StringBuffer.
154      *
155      * @param jvmFormat    The JVM formatted string that is being parsed.
156      * @param i            The offset into the string being parsed.
157      * @param stringbuffer The storage for building the converted method signature.
158      * @return new offset location for parsing.
159      * @TODO this an extremely ugly method (the int an stringbuffer params must be removed)
160      */
161     public static int jvmFormatToJavaFormat(final String jvmFormat, int i, StringBuffer stringbuffer) {;
162         String s1 = "";
163 
164         //arrays.
165         for (; jvmFormat.charAt(i) == '['; i++) {
166             s1 = s1 + "[]";
167         }
168         startover: switch (jvmFormat.charAt(i)) {
169             case 66: // 'B'
170                 stringbuffer.append("byte");
171                 break;
172             case 67: // 'C'
173                 stringbuffer.append("char");
174                 break;
175             case 68: // 'D'
176                 stringbuffer.append("double");
177                 break;
178             case 70: // 'F'
179                 stringbuffer.append("float");
180                 break;
181             case 73: // 'I'
182                 stringbuffer.append("int");
183                 break;
184             case 74: // 'J'
185                 stringbuffer.append("long");
186                 break;
187             case 83: // 'S'
188                 stringbuffer.append("short");
189                 break;
190             case 90: // 'Z'
191                 stringbuffer.append("boolean");
192                 break;
193             case 86: // 'V'
194                 stringbuffer.append("void");
195                 break;
196             case 76: // 'L'
197 
198                 //special case for objects.
199                 for (i++; i < jvmFormat.length(); i++) {
200                     if (jvmFormat.charAt(i) == '/') {
201                         //convert to period
202                         stringbuffer.append('.');
203                     } else {
204                         if (jvmFormat.charAt(i) == ';') {
205                             //we reached the end
206                             break startover;
207                         }
208 
209                         //copy contents.
210                         stringbuffer.append(jvmFormat.charAt(i));
211                     }
212                 }
213                 break;
214             default:
215                 return jvmFormat.length();
216         }
217         stringbuffer = stringbuffer.append(s1);
218         return ++i;
219     }
220 }